package cn.lili.modules.goods.entity.dos;

import cn.hutool.core.convert.Convert;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.http.HtmlUtil;
import cn.hutool.json.JSONUtil;
import cn.lili.common.enums.ResultCode;
import cn.lili.common.exception.ServiceException;
import cn.lili.modules.goods.entity.dto.GoodsOperationDTO;
import cn.lili.modules.goods.entity.enums.GoodsAuthEnum;
import cn.lili.modules.goods.entity.enums.GoodsMarketEnum;
import cn.lili.modules.goods.entity.enums.GoodsTypeEnum;
import cn.lili.modules.goods.entity.enums.SalesModeEnum;
import cn.lili.mybatis.model.BaseSceneEntity;
import com.baomidou.mybatisplus.annotation.FieldStrategy;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableName;
import com.xkcoding.http.util.StringUtil;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;
import org.hibernate.validator.constraints.Length;
import org.springframework.beans.BeanUtils;

import javax.validation.constraints.Max;
import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.NotNull;
import java.io.Serial;
import java.math.BigDecimal;
import java.util.Map;

/**
 * 商品
 *
 * @author pikachu
 * @since 2020-02-23 9:14:33
 */
@EqualsAndHashCode(callSuper = true)
@Data
@TableName("li_goods")
@ApiModel(value = "商品")
@Accessors(chain = true)
@NoArgsConstructor
public class Goods extends BaseSceneEntity {

    @Serial
    private static final long serialVersionUID = 370683495251252601L;


    @ApiModelProperty(value = "商品名称")
    @NotEmpty(message = "商品名称不能为空")
    @Length(max = 100, message = "商品名称太长，不能超过100个字符")
    private String goodsName;

    @ApiModelProperty(value = "商品价格", required = true)
    @NotNull(message = "商品价格不能为空")
    @Min(value = 0, message = "商品价格不能为负数")
    @Max(value = 99999999, message = "商品价格不能超过99999999")
    private Double price;

    @ApiModelProperty(value = "品牌id")
    private String brandId;

    @ApiModelProperty(value = "分类path")
    private String categoryPath;

    @ApiModelProperty(value = "子分类路径，多个按-分割")
    private String categoryPathSon;

    @ApiModelProperty(value = "子分类名称，多个按-分割")
    private String categoryPathSonName;

    @ApiModelProperty(value = "计量单位")
    private String goodsUnit;


    @Length(max = 60, message = "商品卖点太长，不能超过60个字符")
    @ApiModelProperty(value = "卖点")
    private String sellingPoint;

    /**
     * @see GoodsMarketEnum
     */
    @ApiModelProperty(value = "上架状态")
    private String marketEnable;

    @ApiModelProperty(value = "详情")
    private String intro;

    @ApiModelProperty(value = "购买数量")
    private Integer buyCount;

    @Max(value = 99999999, message = "库存不能超过99999999")
    @ApiModelProperty(value = "库存")
    private Integer quantity;

    @ApiModelProperty(value = "商品好评率")
    private Double grade;

    @ApiModelProperty(value = "缩略图路径")
    private String thumbnail;

    @ApiModelProperty(value = "小图路径")
    private String small;

    @ApiModelProperty(value = "原图路径")
    private String original;

    @ApiModelProperty(value = "大图路径")
    private String big;

    @ApiModelProperty(value = "店铺分类id")
    private String storeCategoryPath;

    @ApiModelProperty(value = "评论数量")
    private Integer commentNum;

    @ApiModelProperty(value = "卖家id")
    private String storeId;

    @ApiModelProperty(value = "卖家名字")
    private String storeName;

    @ApiModelProperty(value = "运费模板id")
    private String templateId;

    /**
     * @see GoodsAuthEnum
     */
    @ApiModelProperty(value = "审核状态")
    private String authFlag;

    @ApiModelProperty(value = "审核信息")
    private String authMessage;

    @ApiModelProperty(value = "下架原因")
    private String underMessage;

    @ApiModelProperty(value = "是否自营")
    private Boolean selfOperated;

    @ApiModelProperty(value = "商品移动端详情")
    private String mobileIntro;

    @ApiModelProperty(value = "商品视频")
    @TableField(updateStrategy = FieldStrategy.IGNORED)
    private String goodsVideo;


    @ApiModelProperty(value = "是否为推荐商品", required = true)
    private Boolean recommend;

    /**
     * @see SalesModeEnum
     */
    @ApiModelProperty(value = "销售模式", required = true)
    private String salesModel;


    /**
     * @see cn.lili.modules.goods.entity.enums.GoodsTypeEnum
     */
    @ApiModelProperty(value = "商品类型", required = true)
    private String goodsType;

    @ApiModelProperty(value = "商品参数json", hidden = true)
    private String params;

    @ApiModelProperty(value = "存入索引目标，为空则应该是默认索引", hidden = true)
    private String esIndex;


    @ApiModelProperty(value = "供应商ID")
    private String supplierId;

    @ApiModelProperty(value = "供应商名称")
    private String supplierName;

    @ApiModelProperty(value = "供应商商品ID")
    private String supplierGoodsId;

    @ApiModelProperty(value = "支持代发")
    private Boolean supportProxy;

    @ApiModelProperty(value = "支持采购")
    private Boolean supportPurchase;

    /**
     * @see cn.lili.modules.goods.entity.enums.PurchaseRuleEnum
     */
    @ApiModelProperty(value = "采购规则")
    private String purchaseRule;

    /**
     * @see cn.lili.modules.goods.entity.enums.SupplierEnum
     */
    @ApiModelProperty(value = "供应商类型")
    private String supplierEnum;


    @ApiModelProperty(value = "保留字段1", hidden = true)
    private String field1;

    @ApiModelProperty(value = "保留字段2", hidden = true)
    private String field2;

    @ApiModelProperty(value = "保留字段3", hidden = true)
    private String field3;

    @ApiModelProperty(value = "保留字段4", hidden = true)
    private String field4;

    @ApiModelProperty(value = "保留字段5", hidden = true)
    private String field5;

    @ApiModelProperty(value = "扩展字段，可自由存储，数据库为text格式", hidden = true)
    private String ext;

    @ApiModelProperty(value = "是否是代理商品")
    private Boolean isProxyGoods = false;

    @ApiModelProperty(value = "商品来源，1:手动，2：采集；3：api接口获取", required = true)
    private Integer  goodsFrom;

    @ApiModelProperty(value = "供应链ID")
    private String supplyChainId;

    @ApiModelProperty(value = "商品采集地址", required = true)
    private String goodsGrabUrl;

    @ApiModelProperty(value = "商品价值（盲盒商品专用）")
    private String goodsValue;

    @ApiModelProperty(value = "是否是绿色商品")
    private Boolean isGreenGoods;

    @ApiModelProperty(value = "规则ID")
    private String ruleId;

    @ApiModelProperty(value = "商品默认的sku绿色积分")
    private BigDecimal defaultSkuGreenScore;

    @ApiModelProperty(value = "第三方平台id")
    @TableField(exist = false)
    private Integer gid;

    @ApiModelProperty(value = "第三方供应链平台id")
    private String thirdPartyPlatformId;

    @ApiModelProperty(value = "第三方供应链类型（1壹邦玖，2企叮咚 4,免税）")
    private Integer thirdPartyPlatformType;

    private Integer weight;

    @ApiModelProperty(value = "是否公益商品")
    private Boolean isCommonwealGoods;

    @ApiModelProperty(value = "会员价")
    @TableField(updateStrategy = FieldStrategy.IGNORED)
    private Double vipPrice;

    @ApiModelProperty(value = "是否会员商品")
    @TableField(updateStrategy = FieldStrategy.IGNORED)
    private Boolean isVipGoods;

    @ApiModelProperty(value = "是否新品")
    @TableField(exist = false)
    private Boolean isNew;

    @ApiModelProperty(value = "是否全返商品")
    private Boolean isResultGoods;

    @ApiModelProperty(value = "是否绿色积分卷抵扣")
    private Boolean isGreenSecurities;


    @ApiModelProperty(value = "规格参数")
    private String specParameter;

    @ApiModelProperty(value = "盲盒规则ID")
    private String mhId;

    /**
     * 发布状态，0待发布，1未发布，2已发布
     */
    @ApiModelProperty(value = "发布状态")
    private Integer publishType;

    /**
     * 商品标签
     */
    private Integer goodsTag;
    /**
     * 单品中奖概率
     */
    private BigDecimal probability;

    @ApiModelProperty(value = "是否演唱会门票")
    private Boolean isTicket;

    @ApiModelProperty(value = "是否套餐商品")
    private Boolean isMeal;

    @ApiModelProperty(value = "虚拟购买数量")
    private Integer virtualBuyCount;

    @ApiModelProperty(value = "虚拟评价数量")
    private Integer virtualEvaluateCount;

    @ApiModelProperty(value = "次数")
    private Integer frequency;

    @ApiModelProperty(value = "类型,1默认商品（谢谢惠顾），2非默认")
    private Integer type;

    @ApiModelProperty(value = "是否是分销商品")
    private Boolean isDistributionGoods;

    @ApiModelProperty(value = "商品主键ID")
    @TableField(exist = false)
    private String goodsId;

    @ApiModelProperty(value = "是否开启一级分销")
    private Boolean isLevelDistribution;

    @ApiModelProperty(value = "是否允许取消订单")
    private Boolean isCancel;

    @ApiModelProperty(value = "礼包Id")
    private String packId;

    @ApiModelProperty("礼包名称")
    @TableField(exist = false)
    private String packName;

    /**
     * 是否免税商品
     */
    private Boolean isFree;

    public Double getGrade() {
        //如果没有评分，也没有评论，那么评分为100
        if ((grade == null || grade <= 0) && (commentNum == null || commentNum == 0)) {
            return 100D;
        }
        return grade;
    }

    public Boolean getSupportProxy() {
        if (supportProxy == null) {
            return false;
        }
        return supportProxy;
    }

    public Boolean getSupportPurchase() {
        if (supportPurchase == null) {
            return false;
        }
        return supportPurchase;
    }

    public Boolean getIsProxyGoods() {
        if (isProxyGoods == null) {
            return false;
        }
        return isProxyGoods;
    }

    public Goods(GoodsOperationDTO goodsOperationDTO) {
        BeanUtils.copyProperties(goodsOperationDTO, this);


        if (goodsOperationDTO.getGoodsParamsDTOList() != null && goodsOperationDTO.getGoodsParamsDTOList().isEmpty()) {
            this.params = JSONUtil.toJsonStr(goodsOperationDTO.getGoodsParamsDTOList());
        }
        //如果立即上架则
        this.marketEnable = Boolean.TRUE.equals(goodsOperationDTO.getRelease()) ? GoodsMarketEnum.UPPER.name() : GoodsMarketEnum.DOWN.name();

        this.grade = 100D;

        if (StringUtil.isNotEmpty(goodsOperationDTO.getGoodsId())) {
            this.setId(goodsOperationDTO.getGoodsId());
        }
        //循环sku，判定sku是否有效
        for (Map<String, Object> sku : goodsOperationDTO.getSkuList()) {
            this.checkSkuAvailable(goodsOperationDTO, sku);
        }
    }

    public String getIntro() {
        if (CharSequenceUtil.isNotEmpty(intro)) {
            return HtmlUtil.unescape(intro);
        }
        return intro;
    }

    public String getMobileIntro() {
        if (CharSequenceUtil.isNotEmpty(mobileIntro)) {
            return HtmlUtil.unescape(mobileIntro);
        }
        return mobileIntro;
    }

    /**
     * 检查sku内容有效性
     *
     * @param goodsOperationDTO 商品操作信息
     * @param sku               sku信息
     */
    private void checkSkuAvailable(GoodsOperationDTO goodsOperationDTO, Map<String, Object> sku) {
        //判定参数不能为空
        if (!sku.containsKey(GoodsSku.SN_KEY) || sku.get(GoodsSku.SN_KEY) == null) {
            throw new ServiceException(ResultCode.GOODS_SKU_SN_ERROR);
        }
        if ((!sku.containsKey(GoodsSku.PRICE_KEY) || StringUtil.isEmpty(sku.get(GoodsSku.PRICE_KEY).toString())
                || Convert.toDouble(sku.get(GoodsSku.PRICE_KEY)) <= 0)
                && !goodsOperationDTO.getSalesModel().equals(SalesModeEnum.WHOLESALE.name())
                && !goodsOperationDTO.getSalesModel().equals(SalesModeEnum.PURCHASING.name())) {
            throw new ServiceException(ResultCode.GOODS_SKU_PRICE_ERROR);
        }
        if ((!sku.containsKey(GoodsSku.COST_KEY) || StringUtil.isEmpty(sku.get(GoodsSku.COST_KEY).toString())
                || Convert.toDouble(sku.get(GoodsSku.COST_KEY)) <= 0)
                && !goodsOperationDTO.getSalesModel().equals(SalesModeEnum.WHOLESALE.name())
                && !goodsOperationDTO.getSalesModel().equals(SalesModeEnum.PURCHASING.name())) {
            throw new ServiceException(ResultCode.GOODS_SKU_COST_ERROR);
        }
        //虚拟商品没有重量字段
        if (this.goodsType.equals(GoodsTypeEnum.PHYSICAL_GOODS.name())
                && (!sku.containsKey(GoodsSku.WEIGHT_KEY) || sku.containsKey(GoodsSku.WEIGHT_KEY) && (StringUtil.isEmpty(sku.get(GoodsSku.WEIGHT_KEY).toString())
                || Convert.toDouble(sku.get(GoodsSku.WEIGHT_KEY).toString()) < 0))) {
            throw new ServiceException(ResultCode.GOODS_SKU_WEIGHT_ERROR);
        }
        if (!sku.containsKey(GoodsSku.QUANTITY_KEY)
                || StringUtil.isEmpty(sku.get(GoodsSku.QUANTITY_KEY).toString())
                || Convert.toInt(sku.get(GoodsSku.QUANTITY_KEY).toString()) < 0) {
            throw new ServiceException(ResultCode.GOODS_SKU_QUANTITY_ERROR);
        }
    }

}